﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using adc;

namespace tabtool {
    class CodeGen {
        public static string space_name = "game_data";
        public static List<List<string>> associate_info = new List<List<string>>();
      
        public static void MakeCppFile(List<TableMeta> metalist, string codepath) {
            foreach (var meta in metalist) {
                string hfile = codepath + meta.GetCppFileName();
                using (FileStream fs = new FileStream(hfile, FileMode.Create, FileAccess.Write)){
                    using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                        sw.WriteLine("/*");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | Author: Downey                                                       |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("*/");
                        sw.WriteLine("#pragma once");
                        sw.WriteLine("#include <cstdio>");
                        sw.WriteLine("#include <string>");
                        sw.WriteLine("#include \"adc.hpp\"");
                        sw.WriteLine("#include \"tbs.hpp\"");
                        sw.WriteLine();
                        sw.WriteLine("namespace {0} {{", space_name);
                        sw.WriteLine();
                        //BaseField
                        foreach (var asc in associate_info) {
                            if(asc[0] == meta.TableName) {
                                sw.WriteLine("struct {0};", asc[2]);
                            }
                        }
                        sw.WriteLine("struct {0} {{", meta.GetClassName());
                        if (meta.container_type == TableFieldType.map_type) {
                            sw.WriteLine("\ttypedef {0} key_type;", meta.Fields[0].GetCppTypeName());
                        }
                        foreach (var field in meta.Fields) {
                            sw.WriteLine("\t{0} {1};  //{2}", field.GetCppTypeName(), field.fieldName, field.fieldDesc);
                        }
                        foreach (var asc in associate_info) {
                            if (asc[0] == meta.TableName) {
                                sw.WriteLine("\t::std::vector<const {0} *> __asc__{0}//\tassociate {0}", asc[2]);
                            }
                        }
                        sw.WriteLine("\tvoid* __user_data = nullptr;");
                        //VaildFuction
                        sw.WriteLine("\tinline static void valid(::adc::data_define const& def) {");
                        sw.WriteLine("\t\tif(def.fields.size() != {0}) throw std::logic_error(\"field_count invalid!\");", meta.Fields.Count());
                        StringBuilder builder = new StringBuilder();
                        for (int i = 0; i < meta.Fields.Count; ++i) {
                            sw.WriteLine("\t\t{");
                            builder.Clear();
                            builder.Append("\t\t\tuint8_t types[] = {");
                            int len = meta.BuildCppStr(builder, meta.Fields[i].type);
                            builder.Append("};");
                            sw.WriteLine(builder.ToString());
                            sw.WriteLine("\t\t\tif(!valid_filed(def.fields[{0}], \"{1}\", types, {2}))", i, meta.Fields[i].fieldName, len);
                            sw.WriteLine("\t\t\t\tthrow std::logic_error(\"field {0} not match!\");", meta.Fields[i].fieldName);
                            sw.WriteLine("\t\t}");
                        }
                        sw.WriteLine("\t}");
                        sw.WriteLine("");
                        //LoadFunction
                        if (meta.container_type == TableFieldType.map_type) {
                            sw.WriteLine("\tinline {0} load(::adc::data_define const &def, ::adata::zero_copy_buffer& zbuf) {{", meta.Fields[0].GetCppTypeName());
                        } else if(meta.container_type == TableFieldType.list_type) {
                            sw.WriteLine("\tinline void load(::adc::data_define const &def, ::adata::zero_copy_buffer& zbuf) {");
                        }
                        for (int i = 0; i < meta.Fields.Count; ++i) {
                            sw.WriteLine("\t\t{{::adc::load_value(zbuf, this->{0}, def);}}", meta.Fields[i].fieldName);
                            sw.WriteLine("\t\t::adc::util::check_zbuf(zbuf, \"error read {0}\");", meta.Fields[i].fieldName);
                        }
                        if (meta.container_type == TableFieldType.map_type) {
                            sw.WriteLine("\t\treturn this->{0};", meta.Fields[0].fieldName);
                        }
                        sw.WriteLine("\t}");
                        sw.WriteLine("};");
                        //TypeDef
                        sw.WriteLine("typedef ::adc::{0}<{1}> adc_{1}_t;", meta.GetContainerType(), meta.GetClassName());
                        sw.WriteLine("}");
                    }
                } 
            }

            //recombine
            foreach (var asc in associate_info) {
                if (asc[4] == ">") {
                    TableMeta tmp_meta = null;
                    //去服务器表中查找聚合源 如果没找到证明忽略了
                    foreach (var meta in metalist) {
                        if (meta.TableName == asc[2]) {
                            tmp_meta = meta;
                            break;
                        }
                    }
                    if (tmp_meta == null) continue;
                    string file = codepath + "adc_" + asc[0] + ".hpp";
                    using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write)) {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                            sw.WriteLine("/*");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | Author: Downey                                                       |");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("*/");
                            sw.WriteLine();
                            sw.WriteLine("#pragma once");
                            sw.WriteLine("#include <cstdio>");
                            sw.WriteLine("#include <string>");
                            sw.WriteLine("#include \"adc.hpp\"");
                            sw.WriteLine("#include \"tbs.hpp\"");
                            sw.WriteLine("namespace {0}  {{", space_name);
                            sw.WriteLine("struct {0};", asc[2]);
                            foreach (var _asc in associate_info) {
                                if (asc[0] == _asc[0] && _asc[4] != ">") {
                                    sw.WriteLine("struct {0};", _asc[2]);
                                }
                            }
                            sw.WriteLine("struct {0} {{", asc[0]);
                            sw.WriteLine("\ttypedef {0} key_type;", tmp_meta.Fields[0].GetCppTypeName());
                            sw.WriteLine("\t{0} {1};", tmp_meta.Fields[0].GetCppTypeName(), asc[1]);
                            sw.WriteLine("\t::std::vector<const {0} *> __asc__{0};\t//recombine {0}", asc[2]);
                            foreach (var _asc in associate_info) {
                                if (asc[0] == _asc[0] && _asc[4] != ">") {
                                    sw.WriteLine("\t::std::vector<const {0} *> __asc__{0};\t//associate {0}", _asc[2]);
                                }
                            }
                            //VaildFuction
                            sw.WriteLine("\tinline static void valid(::adc::data_define const& def) {");
                            sw.WriteLine("\t\tif(def.fields.size() != 1) throw std::logic_error(\"field_count invalid!\");");
                            StringBuilder builder = new StringBuilder();
                            builder.Append("\t\tuint8_t types[] = {");
                            int len = tmp_meta.BuildCppStr(builder, tmp_meta.Fields[0].type);
                            builder.Append("};");
                            sw.WriteLine(builder.ToString());
                            sw.WriteLine("\t\tif(!valid_filed(def.fields[0], \"{0}\", types, 1))", asc[1]);
                            sw.WriteLine("\t\t\tthrow std::logic_error(\"field {0} not match!\");", asc[1]);
                            sw.WriteLine("\t}");

                            sw.WriteLine("\t//load_function");
                            sw.WriteLine("\tinline {0} load(::adc::data_define const &def, ::adata::zero_copy_buffer& zbuf) {{", tmp_meta.Fields[0].GetCppTypeName());
                            sw.WriteLine("\t\t{{::adc::load_value(zbuf, this->{0}, def);}}", asc[1]);
                            sw.WriteLine("\t\t::adc::util::check_zbuf(zbuf, \"error read {0}\");", asc[1]);
                            sw.WriteLine("\t\treturn {0};", asc[1]);          
                            sw.WriteLine("\t}");
                            sw.WriteLine("};");
                            //TypeDef
                            sw.WriteLine("typedef ::adc::map<{0}> adc_{0}_t;", asc[0]);
                            sw.WriteLine("}");
                        }
                    }
                }
            }


            string cppfile = codepath + "adc_load.cpp";
            using (FileStream fs = new FileStream(cppfile, FileMode.Create, FileAccess.Write)){
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine("/*");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | Author: Downey                                                       |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("*/");
                    sw.WriteLine("#include <iostream>");
                    sw.WriteLine("#include \"adc.hpp\"");
                    sw.WriteLine();
                    foreach (var meta in metalist) {
                        sw.WriteLine("#include \"{0}\"", meta.GetCppFileName());
                        sw.WriteLine("namespace adc {");
                        sw.WriteLine("{0}::adc_{1}_t the_adc_{1}_;", space_name, meta.GetClassName());
                        sw.WriteLine("template<> ::{0}::adc_{1}_t const& adc_get<::{0}::adc_{1}_t>() {{", space_name, meta.GetClassName());
                        sw.WriteLine("\treturn the_adc_{0}_;", meta.GetClassName());
                        sw.WriteLine("}");
                        sw.WriteLine("}");
                    }
                    foreach (var asc in associate_info) {
                        if (asc[4] == ">") {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find)
                                continue;
                            sw.WriteLine("#include \"adc_{0}.hpp\"", asc[0]);
                            sw.WriteLine("namespace adc {");
                            sw.WriteLine("{0}::adc_{1}_t the_adc_{1}_;", space_name, asc[0]);
                            sw.WriteLine("template<> ::{0}::adc_{1}_t const& adc_get<::{0}::adc_{1}_t>() {{", space_name, asc[0]);
                            sw.WriteLine("\treturn the_adc_{0}_;", asc[0]);
                            sw.WriteLine("}");
                            sw.WriteLine("}");
                        }
                    }
                    sw.WriteLine();
                    sw.WriteLine("namespace {0} {{", space_name);
                    sw.WriteLine("\tvoid load_all_data() {");
                    sw.WriteLine("\t\t::adc::pack_loader loader;");
                    sw.WriteLine("\t\t::adc::load(\"all_data.adc\", loader);");
                    int rec_count = 0;
                    foreach (var asc in associate_info) {
                        if (asc[4] == ">") {
                            foreach (var m in metalist) {
                                if (m.TableName == asc[2])
                                    ++rec_count;
                            }
                        }
                    }
                    sw.WriteLine("\t\tif(loader.count != {0}) {{std::cerr << \"Package Count Not Match!\" << std::endl; throw ::std::logic_error(\"Package Count Not Match!\");}}", metalist.Count + rec_count);
                    foreach (var meta in metalist) {
                        sw.WriteLine("\t\ttry{{::adc::load(::adc::the_adc_{0}_,loader.buf);}}catch(std::exception& e){{std::cerr << \"error type:\" << \"{0}\" << e.what(); throw e;}}", meta.GetClassName());
                    }
                    foreach (var asc in associate_info) {
                        if (asc[4] == ">") {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find)
                                continue;
                            sw.WriteLine("\t\ttry{{::adc::load(::adc::the_adc_{0}_,loader.buf);}}catch(std::exception& e){{std::cerr << \"error type:\" << \"{0}\" << e.what(); throw e;}}", asc[0]);
                        }
                    }
                    sw.WriteLine("\t\t//associate code");
                    foreach (var asc in associate_info) {
                        if (asc[4] == ">") {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find) continue;
                        } else {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find) continue;
                            find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[0]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find) {
                                foreach (var _asc in associate_info) {
                                    if (_asc[4] == ">" && _asc[0] == asc[0]) {
                                        foreach (var meta in metalist) {
                                            if (meta.TableName == _asc[2]) {
                                                find = true;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            if (!find) continue;
                        }
                        sw.WriteLine("\t\tfor(auto p1 = ::adc::the_adc_{0}_.value().begin() ; p1 != ::adc::the_adc_{0}_.value().end(); ++p1) {{", asc[0]);
                        sw.WriteLine("\t\t\t{0}& v1 = ({0}&)p1->second;", asc[0]);
                        sw.WriteLine("\t\t\tauto const& k1 = v1.{0};", asc[1]);
                        sw.WriteLine("\t\t\tfor(auto p2 = ::adc::the_adc_{0}_.value().begin() ; p2 != ::adc::the_adc_{0}_.value().end(); ++p2) {{", asc[2]);
                        sw.WriteLine("\t\t\t\t{0} const& v2 = *p2;", asc[2]);
                        sw.WriteLine("\t\t\t\tauto const& k2 = v2.{0};", asc[3]);
                        sw.WriteLine("\t\t\t\tif(k1 == k2) {");
                        sw.WriteLine("\t\t\t\t\tv1.__asc__{0}.push_back(&v2);", asc[2]);
                        sw.WriteLine("\t\t\t\t}");
                        sw.WriteLine("\t\t\t}");
                        sw.WriteLine("\t\t}");
                    }
                    sw.WriteLine("\t}");
                    sw.WriteLine("}");

                }
            }
        }
        public static void MakeCppFileTbs(List<TableMeta> metalist, string codepath) {
            string hfile = codepath + "tbs.hpp";
            using (FileStream fs = new FileStream(hfile, FileMode.Create, FileAccess.Write)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine("/*");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | Author: Downey                                                       |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("*/");
                    sw.WriteLine();
                    sw.WriteLine("#pragma once");
                    sw.WriteLine("namespace {0} {{", space_name);
                    foreach (var meta in metalist) {
                        sw.WriteLine("struct {0} {{", meta.TableName);
                        foreach (var field in meta.Fields) {
                            sw.WriteLine("\t{0} {1};", field.GetCppTypeName(), field.fieldName);
                        }
                        sw.WriteLine("\tvoid load_value(::adata::zero_copy_buffer& zbuf, ::adc::data_define const& def) {");
                        for (int i = 0; i < meta.Fields.Count(); i++) {
                            var field = meta.Fields[i];
                            sw.WriteLine("\t\t{{::adc::load_value(zbuf, this->{0}, def);}}", field.fieldName);
                        }
                        sw.WriteLine("\t}");
                        sw.WriteLine("};");
                        sw.WriteLine("");
                    }
                    sw.WriteLine("}");
                }
            }
        }
        public static void MakeCsharpFileTbs(List<TableMeta> metalist, string codepath)
        {
            string hfile = codepath + "tbs.cs";
            using (FileStream fs = new FileStream(hfile, FileMode.Create, FileAccess.Write)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine("/*");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | Author: Downey                                                       |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("*/");
                    sw.WriteLine();
                    sw.WriteLine("using System;"); 
                    sw.WriteLine("using System.Collections.Generic;");
                    sw.WriteLine("using adc;");
                    sw.WriteLine("namespace {0} {{", space_name);
                    foreach (var meta in metalist) {
                        sw.WriteLine("public class {0} : interface_read_value {{", meta.TableName);
                        foreach (var field in meta.Fields) {
                            sw.WriteLine("\t{0} {1};", field.GetCsharpTypeName(), field.fieldName);
                        }
                        sw.WriteLine("\tvoid interface_read_value.read_value(adata.zero_copy_buffer zbuf, string[] pool, List<base_type> elem_types) {");
                        for (int i = 0; i < meta.Fields.Count(); i++) {
                            var field = meta.Fields[i];
                            sw.WriteLine("\t\t{0} = ({3})elem_types[{1}].read_value<{2}>(zbuf, pool);", field.fieldName, i, field.GetCsharpTemplateType(), field.GetCsharpTypeName());
                        }
                        sw.WriteLine("\t}");
                        sw.WriteLine("}");
                        sw.WriteLine("");
                    }
                    sw.WriteLine("}");
                }
            }
        }
        public static void MakeCsharpFile(List<TableMeta> metalist, string codepath)
        {
            foreach (var meta in metalist) {
                string csfile = codepath + meta.GetCsharpFileName();
                using (FileStream fs = new FileStream(csfile, FileMode.Create, FileAccess.Write)) {
                    using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                        sw.WriteLine("/*");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | Author: Downey                                                       |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("*/");
                        sw.WriteLine();
                        sw.WriteLine("using System;");
                        sw.WriteLine("using System.Collections;");
                        sw.WriteLine("using System.Collections.Generic;");
                        sw.WriteLine("using adata;");
                        sw.WriteLine("using adc;");
                        sw.WriteLine("namespace {0}  {{", space_name);
                        sw.WriteLine("public class {0} : interface_load {{", meta.GetClassName());
                        foreach (var field in meta.Fields) {
                            sw.WriteLine("\tpublic {0} {1};\t//{2}", field.GetCsharpTypeName(), field.fieldName, field.fieldDesc);
                        }
                        foreach (var asc in associate_info) {
                            if (asc[0] == meta.TableName) {//
                                bool find = false;
                                foreach (var m in metalist) {
                                    if (m.TableName == asc[2]) {
                                        find = true;
                                        break;
                                    }
                                }
                                if (!find)
                                    continue;
                                sw.WriteLine("\tpublic List<{0}> __asc__{0} = new List<{0}>();\t//associate {0}", asc[2]);
                            }
                        }

                        //vaild_function
                        sw.WriteLine("\t//load_function");
                        if (meta.container_type == TableFieldType.map_type) {
                            sw.WriteLine("\tobject interface_load.load(adc_def def, adata.zero_copy_buffer zbuf) {"/*, meta.Fields[0].GetCsharpTypeName()*/);
                        } else if (meta.container_type == TableFieldType.list_type) {
                            sw.WriteLine("\tobject interface_load.load(adc_def def, adata.zero_copy_buffer zbuf) {");
                        }
                        for (int i = 0; i < meta.Fields.Count; ++i) {
                            sw.WriteLine("\t\t{{{0} = ({1})def.fields[{2}].type.read_value<{3}>(zbuf, def.string_pool);}}", meta.Fields[i].fieldName, meta.Fields[i].GetCsharpTypeName(), i, meta.Fields[i].GetCsharpTemplateType());
                            sw.WriteLine("\t\tloader.check_zbuf(zbuf, \"error read {0}\");", meta.Fields[i].fieldName);
                        }
                        if (meta.container_type == TableFieldType.map_type) {
                            sw.WriteLine("\t\treturn {0};", meta.Fields[0].fieldName);
                        } else if (meta.container_type == TableFieldType.list_type) {
                            sw.WriteLine("\t\treturn null;");
                        }
                        sw.WriteLine("\t}");
                        sw.WriteLine("}");

                        sw.WriteLine("}");
                        sw.WriteLine();
                    }
                }
            }
      
            foreach (var asc in associate_info) {
                if(asc[4] == ">") {
                    TableMeta tmp_mate = null;
                    //去客户端表中查找聚合源 如果没找到证明忽略了
                    foreach (var meta in metalist) {
                        if (meta.TableName == asc[2]) {
                            tmp_mate = meta;
                            break;
                        }
                    }
                    if (tmp_mate == null) continue;

                    string file = codepath + "adc_" + asc[0] + ".cs";
                    using (FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write)) {
                        using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                            sw.WriteLine("/*");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("   | Author: Downey                                                       |");
                            sw.WriteLine("   +----------------------------------------------------------------------+");
                            sw.WriteLine("*/");
                            sw.WriteLine();
                            sw.WriteLine("using System;");
                            sw.WriteLine("using System.Collections;");
                            sw.WriteLine("using System.Collections.Generic;");
                            sw.WriteLine("using adata;");
                            sw.WriteLine("using adc;");
                            sw.WriteLine("namespace {0}  {{", space_name);
                            sw.WriteLine("public class {0} : interface_load {{", asc[0]);
                            sw.WriteLine("\tpublic {0} {1};\t//", tmp_mate.Fields[0].GetCsharpTypeName(), asc[1]);
                            sw.WriteLine("\tpublic List<{0}> __asc__{0} = new List<{0}>();\t//recombine {0}", asc[2]);
                            foreach (var _asc in associate_info) {
                                if (asc[0] == _asc[0] && _asc[4] != ">") {
                                    sw.WriteLine("\tpublic List<{0}> __asc__{0} = new List<{0}>();\t//associate {0}", _asc[2]);
                                }
                            }
                            sw.WriteLine("\t//load_function");
                            sw.WriteLine("\tobject interface_load.load(adc_def def, adata.zero_copy_buffer zbuf) {");                
                            sw.WriteLine("\t\t{{{0} = ({1})def.fields[0].type.read_value<{2}>(zbuf, def.string_pool);}}", asc[1], tmp_mate.Fields[0].GetCsharpTypeName(), tmp_mate.Fields[0].GetCsharpTemplateType());
                            sw.WriteLine("\t\tloader.check_zbuf(zbuf, \"error read {0}\");", asc[1]);
                            sw.WriteLine("\t\treturn {0};", asc[1]);
                            sw.WriteLine("\t}");
                            sw.WriteLine("}");
                            sw.WriteLine("}");
                        }
                    }
                }
            }
            string csharpfile = codepath + "adc_load.cs";
            using (FileStream fs = new FileStream(csharpfile, FileMode.Create, FileAccess.Write)) {
                using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8)) {
                    sw.WriteLine("/*");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("   | Author: Downey                                                       |");
                    sw.WriteLine("   +----------------------------------------------------------------------+");
                    sw.WriteLine("*/");
                    sw.WriteLine();
                    sw.WriteLine("using System;");
                    sw.WriteLine("using adc;");
                    sw.WriteLine("using {0};", space_name);
                    sw.WriteLine("");
                    sw.WriteLine("class config_helper {");
                    foreach (var meta in metalist) {
                        sw.WriteLine("\tstatic public {1}<{0}> the_adc_{0}_ = new {1}<{0}>();", meta.GetClassName(), meta.GetContainerType());
                    }
                    foreach (var asc in associate_info) {
                        if(asc[4] == ">") {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find)
                                continue;
                            sw.WriteLine("\tstatic public map<{0}> the_adc_{0}_ = new map<{0}>();", asc[0]);
                        }
                    }
                    sw.WriteLine("");
                    sw.WriteLine("\tpublic static void load_all_data() {");
                    sw.WriteLine("\t\tadc.loader loader = new adc.loader();");
                    sw.WriteLine("\t\tvar count = loader.load_pack(\"all_data.adc\");");
                    int rec_count = 0;
                    foreach (var asc in associate_info) {
                        if (asc[4] == ">") {
                            foreach (var m in metalist) {
                                if (m.TableName == asc[2])
                                    ++rec_count;
                            }
                        }
                    }
                    sw.WriteLine("\t\tif(count != {0}) {{throw new Exception(\"Package Count Not Match!\");}}", metalist.Count + rec_count);
                    foreach (var meta in metalist) {
                        sw.WriteLine("\t\ttry{{loader.load(ref the_adc_{0}_);}}catch(Exception e){{throw new Exception(\"load {0} error!!\" + e.ToString()); }};", meta.GetClassName());
                    }
                    foreach (var asc in associate_info) {
                        if (asc[4] == ">") {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find)
                                continue;
                            sw.WriteLine("\t\ttry{{loader.load(ref the_adc_{0}_);}}catch(Exception e){{throw new Exception(\"load adc_{0} error!!\" + e.ToString()); }};", asc[0]);
                        }
                    }
                    sw.WriteLine("\t\t//associate code");
                    foreach (var asc in associate_info) {
                        if(asc[4] == ">") {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find) continue;
                        } else {
                            bool find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[2]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find) continue;
                            find = false;
                            foreach (var meta in metalist) {
                                if (meta.TableName == asc[0]) {
                                    find = true;
                                    break;
                                }
                            }
                            if (!find) {
                                foreach (var _asc in associate_info) {
                                    if (_asc[4] == ">" && _asc[0] == asc[0]) {
                                        foreach (var meta in metalist) {
                                            if (meta.TableName == _asc[2]) {
                                                find = true;
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            if (!find) continue;
                        }

                        sw.WriteLine("\t\tforeach(var p1 in the_adc_{0}_.adc_get()) {{", asc[0]);
                        sw.WriteLine("\t\t\tforeach(var p2 in the_adc_{0}_.adc_get()) {{", asc[2]);
                        sw.WriteLine("\t\t\t\tif(p1.{0} == p2.{1}) {{", asc[1], asc[3]);
                        sw.WriteLine("\t\t\t\t\tp1.__asc__{0}.Add(p2);", asc[2]);
                        sw.WriteLine("\t\t\t\t}");
                        sw.WriteLine("\t\t\t}");
                        sw.WriteLine("\t\t}");                          
                    }                   
                    sw.WriteLine("\t}");
                    sw.WriteLine("}");
                }
            }
        }
        public static void MakeCppEnumAndMask(string excel_path, string codepath) {
            List<string> files = new List<string>();
            files.AddRange(Directory.GetFiles(excel_path + "/Enum/", "*.xlsm", SearchOption.TopDirectoryOnly));
            files.AddRange(Directory.GetFiles(excel_path + "/Mask/", "*.xlsm", SearchOption.TopDirectoryOnly));
            ExcelHelper helper = new ExcelHelper();
            foreach (string filepath in files) {
                try {
                    DataTable dt = helper.ImportExcelFile(filepath);
                    string filename = Path.GetFileNameWithoutExtension(filepath);
                    string path = codepath + filename + ".h";
                    using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
                        StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
                        sw.WriteLine("/*");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("   | Author: Downey                                                       |");
                        sw.WriteLine("   +----------------------------------------------------------------------+");
                        sw.WriteLine("*/");
                        sw.WriteLine("#pragma once");
                        sw.WriteLine("namespace {0} {{", filename);
                        sw.WriteLine("\tenum {0} {{", filename);
                        for (int i = 0; i < dt.Rows.Count; i++) {
                            sw.WriteLine("\t\t{0} = {1}, //{2}", dt.Rows[i].ItemArray[1].ToString(), dt.Rows[i].ItemArray[0].ToString().ToLower(), dt.Rows[i].ItemArray[2].ToString());
                        }
                        sw.WriteLine("\t};");
                        sw.WriteLine("\tinline char const* {0}_to_string(int val) {{", filename);
                        sw.WriteLine("\t\tswitch(val) {");
                        for (int i = 0; i < dt.Rows.Count; i++) {
                            sw.WriteLine("\t\t\tcase {0}:{{ return \"{1}\";}}", dt.Rows[i].ItemArray[1].ToString(), dt.Rows[i].ItemArray[1].ToString());
                        }
                        sw.WriteLine("\t\t\tdefault:{ return \"\";}");
                        sw.WriteLine("\t\t}");
                        sw.WriteLine("\t};");
                        sw.WriteLine("}");
                        sw.Close();
                    }
                } catch (Exception e) {
                    Console.WriteLine(filepath + " 文件出错！");
                    Console.WriteLine(e.ToString());
                }
            }
            Console.WriteLine("+------------------+");
            Console.WriteLine("<生成C++枚举掩码成功>");
        }
        public static void MakeCsharpEnumAndMask(string excel_path, string codepath){
            List<string> files = new List<string>();
            files.AddRange(Directory.GetFiles(excel_path + "/Enum/", "*.xlsm", SearchOption.TopDirectoryOnly));
            files.AddRange(Directory.GetFiles(excel_path + "/Mask/", "*.xlsm", SearchOption.TopDirectoryOnly));
            ExcelHelper helper = new ExcelHelper();
            string path = codepath + "enum_types.cs";
            using (FileStream fs = new FileStream(path, FileMode.Create, FileAccess.Write)) {
                StreamWriter sw = new StreamWriter(fs, Encoding.UTF8);
                sw.WriteLine("/*");
                sw.WriteLine("   +----------------------------------------------------------------------+");
                sw.WriteLine("   | THIS FILE IS GENERATED BY TABTOOL                                    |");
                sw.WriteLine("   +----------------------------------------------------------------------+");
                sw.WriteLine("   | GENERATE TIME [{0}]                                   |", System.DateTime.Now.ToString());
                sw.WriteLine("   +----------------------------------------------------------------------+");
                sw.WriteLine("   | DO NOT EDIT IT!                                                      |");
                sw.WriteLine("   +----------------------------------------------------------------------+");
                sw.WriteLine("   | Author: Downey                                                       |");
                sw.WriteLine("   +----------------------------------------------------------------------+");
                sw.WriteLine("*/");
                sw.WriteLine("namespace {0} {{", space_name);
                foreach (string filepath in files) {
                    try {
                        DataTable dt = helper.ImportExcelFile(filepath);
                        string filename = Path.GetFileNameWithoutExtension(filepath).ToLower();
                        
                        sw.WriteLine("\tpublic enum {0} {{", filename);
                        for (int i = 0; i < dt.Rows.Count; i++) {
                            sw.WriteLine("\t\t{0} = {1}, //{2}", dt.Rows[i].ItemArray[1].ToString(), dt.Rows[i].ItemArray[0].ToString().ToLower(), dt.Rows[i].ItemArray[2].ToString().ToLower());
                        }
                        sw.WriteLine("\t};");
                    } catch (Exception e) {
                        Console.WriteLine(filepath + " 文件出错！");
                        Console.WriteLine(e.ToString());
                    }
                }
                sw.WriteLine("class type_to_string {");
                foreach (string filepath in files) {
                    try {
                        DataTable dt = helper.ImportExcelFile(filepath);
                        string filename = Path.GetFileNameWithoutExtension(filepath).ToLower();
                        sw.WriteLine("\tstatic string {0}_to_string(int val) {{", filename);
                        sw.WriteLine("\t\tswitch (val) {");
                        for (int i = 0; i < dt.Rows.Count; i++) {
                            sw.WriteLine("\t\t\tcase (int){0}.{1}: {{ return \"{1}\"; }}", filename, dt.Rows[i].ItemArray[1].ToString());
                        }
                        sw.WriteLine("\t\t\tdefault: {return \"\";}");
                        sw.WriteLine("\t\t}");
                        sw.WriteLine("\t}");
                    } catch (Exception e) {
                        Console.WriteLine(filepath + " 文件出错！");
                        Console.WriteLine(e.ToString());
                    }
                }
                sw.WriteLine("};");
                sw.WriteLine("}");
                sw.Close();
            }          
            Console.WriteLine("+------------------+");
            Console.WriteLine("<生成C#枚举掩码成功>");
        }


        public static void DelectDir(string srcPath)
        {
            try {
                DirectoryInfo dir = new DirectoryInfo(srcPath);
                FileSystemInfo[] fileinfo = dir.GetFileSystemInfos();  //返回目录中所有文件和子目录
                foreach (FileSystemInfo i in fileinfo) {
                    if (i is DirectoryInfo)            //判断是否文件夹
                    {
                        DirectoryInfo subdir = new DirectoryInfo(i.FullName);
                        subdir.Delete(true);          //删除子目录和文件
                    } else {
                        File.Delete(i.FullName);      //删除指定文件
                    }
                }
            } catch (Exception e) {
                throw;
            }
        }

    }

}